#include "stdafx.h"
#include "FluidView.h"

#include "GlobalAppData.h"
#include "LoadShader.h"
#include "InputLayouts.h"
#include "LoadTexture.h"

#include "Renderer.h"

#include "TextField.h"
#include "OnOffButton.h"
#include "PushButton.h"
#include "Label.h"
#include "Window.h"

#include <ctime>

using namespace mfluid;

#define IDX(x,y) ((y)*(FLUID_GRID_SIZE_X + 2) + (x))

static float densitySources[FLUID_PROPERTY_ARRAY_SIZE];
static float velXSources[FLUID_PROPERTY_ARRAY_SIZE];
static float velYSources[FLUID_PROPERTY_ARRAY_SIZE];
static float divergence[FLUID_PROPERTY_ARRAY_SIZE];
static float pressure[FLUID_PROPERTY_ARRAY_SIZE];

static bool sDiffuseDensity = true;
static int sProjNumIter = 20;

static void addSources (float * __restrict densities, float * __restrict sources, float dt)
{
	for(size_t i = 0; i < FLUID_PROPERTY_ARRAY_SIZE; i++)
	{
		//densities[i] = (std::min)(densities[i] + dt * sources[i], 100.0f);
		densities[i] = densities[i] + dt * sources[i];
		sources[i] = 0;
	}
}

static void setBoundary(int b, float * v)
{
	size_t NX = FLUID_GRID_SIZE_X;
	size_t NY = FLUID_GRID_SIZE_Y;

	for(size_t x = 1; x <= NX; x++)
	{
		v[IDX(x, 0)] = b == 2 ? -v[IDX(x, 1)] : v[IDX(x, 1)];
		v[IDX(x, NY+1)] = b == 2 ? -v[IDX(x, NY)] : v[IDX(x, NY)];
	}

	for(size_t y = 1; y <= NY; y++)
	{
		v[IDX(0, y)] = b == 1 ? -v[IDX(1, y)] : v[IDX(1, y)];
		v[IDX(NX+1, y)] = b == 1 ? -v[IDX(NX, y)] : v[IDX(NX, y)];
	}

	v[IDX(0, 0)] = 0.5f * (v[IDX(1, 0)] + v[IDX(0, 1)]);
	v[IDX(0, NY+1)] = 0.5f * (v[IDX(1, NY+1)] + v[IDX(0, NY)]);

	v[IDX(NX+1, 0)] = 0.5f * (v[IDX(NX, 0)] + v[IDX(NX+1, 1)]);
	v[IDX(NX+1, NY+1)] = 0.5f * (v[IDX(NX, NY+1)] + v[IDX(NX+1, NY)]);
}

static void diffuse0(int b, float * v1, float * v0, float diff, float dt)
{
	float a = dt * diff;

		for(size_t y = 1; y <= FLUID_GRID_SIZE_Y; y++)
		{
			for(size_t x = 1; x <= FLUID_GRID_SIZE_X; x++)
			{
				float value = v0[IDX(x, y)];
				value += a * (v0[IDX(x-1, y)] + v0[IDX(x+1, y)] +
							  v0[IDX(x, y-1)] + v0[IDX(x, y+1)] - 4*v0[IDX(x, y)]);

				v1[IDX(x, y)] = value;
			}
		}
		setBoundary ( b, v1 );
}

static void diffuse(int b, float * v1, float * v0, float diff, float dt)
{
	float a = dt * diff * FLUID_GRID_SIZE_X * FLUID_GRID_SIZE_Y;

	for(uint iter = 0; iter < 20; iter++)
	{
		for(size_t y = 1; y <= FLUID_GRID_SIZE_Y; y++)
		{
			for(size_t x = 1; x <= FLUID_GRID_SIZE_X; x++)
			{
				float value = v0[IDX(x, y)];
				value += a * (v1[IDX(x-1, y)] + v1[IDX(x+1, y)] +
									  v1[IDX(x, y-1)] + v1[IDX(x, y+1)]);
				value /= (1 + 4*a);

				v1[IDX(x, y)] = value;
			}
		}
		setBoundary ( b, v1 );
	}
}

static void project(float * u, float * v, float * p, float * div)
{

	float hX = 1.0f / FLUID_GRID_SIZE_X;
	float hY = 1.0f / FLUID_GRID_SIZE_Y;

	for(size_t y = 1; y <= FLUID_GRID_SIZE_Y; y++)
	{
		for(size_t x = 1; x <= FLUID_GRID_SIZE_X; x++)
		{
			div[IDX(x, y)] = -0.5f * (hX * (u[IDX(x+1, y)] - u[IDX(x-1, y)]) +
									  hY * (v[IDX(x, y+1)] - v[IDX(x, y-1)]));
			p[IDX(x, y)] = 0;
		}
	}

	setBoundary ( 0, div );
	setBoundary ( 0, p );

	for(uint k = 0; k < sProjNumIter; k++)
	{
		for(size_t y = 1; y <= FLUID_GRID_SIZE_Y; y++)
		{
			for(size_t x = 1; x <= FLUID_GRID_SIZE_X; x++)
			{
				p[IDX(x, y)] = (div[IDX(x, y)] + p[IDX(x-1, y)] + p[IDX(x+1, y)] + p[IDX(x, y-1)] + p[IDX(x, y+1)])/4;
			}
		}
		setBoundary ( 0, p );
	}

	for(size_t y = 1; y <= FLUID_GRID_SIZE_Y; y++)
	{
		for(size_t x = 1; x <= FLUID_GRID_SIZE_X; x++)
		{
			u[IDX(x, y)] -= 0.5f * (p[IDX(x+1, y)] - p[IDX(x-1, y)]) / hX;
			v[IDX(x, y)] -= 0.5f * (p[IDX(x, y+1)] - p[IDX(x, y-1)]) / hY;
		}
	}

	setBoundary ( 1, u );
	setBoundary ( 2, v );
}

static void advect(int b, float * v1, float * v0, float * velX, float * velY, float dt)
{
	dt *= FLUID_GRID_SIZE_X;

	for(size_t y = 1; y <= FLUID_GRID_SIZE_Y; y++)
	{
		for(size_t x = 1; x <= FLUID_GRID_SIZE_X; x++)
		{
			float xPrev = x - dt * velX[IDX(x, y)];
			float yPrev = y - dt * velY[IDX(x, y)];

			xPrev = (std::max)(xPrev, 0.5f);
			xPrev = (std::min)(xPrev, FLUID_GRID_SIZE_X + 0.5f);

			size_t xP0 = (size_t)xPrev;
			size_t xP1 = xP0 + 1;

			yPrev = (std::max)(yPrev, 0.5f);
			yPrev = (std::min)(yPrev, FLUID_GRID_SIZE_Y + 0.5f);

			size_t yP0 = (size_t)yPrev;
			size_t yP1 = yP0 + 1;

			float s0 = xP1 - xPrev;
			float s1 = 1 - s0;
			float t0 = yP1 - yPrev;
			float t1 = 1 - t0;

			v1[IDX(x, y)] = s0 * (t0 * v0[IDX(xP0, yP0)] + t1 * v0[IDX(xP0, yP1)]) +
							s1 * (t0 * v0[IDX(xP1, yP0)] + t1 * v0[IDX(xP1, yP1)]);
		}
	}
	setBoundary ( b, v1 );
}

void FluidView::reset()
{
	for(uint y = 0; y < FLUID_GRID_SIZE_Y + 2; y++)
	{
		for(uint x = 0; x < FLUID_GRID_SIZE_X + 2; x++)
		{
			XMVECTOR p = XMVectorSet(x, y, 0, 0);

			mFluidDensity[IDX(x,y)] = 0;

			densitySources[IDX(x,y)] = 0;

			mFluidVelX[IDX(x,y)] = 0;
			mFluidVelY[IDX(x,y)] = 0;

			mFluidVelXPrev[IDX(x,y)] = mFluidVelX[IDX(x,y)];
			mFluidVelYPrev[IDX(x,y)] = mFluidVelY[IDX(x,y)];

		}
	}
}

void FluidView::blow()
{
	//for(uint y = 0; y < FLUID_GRID_SIZE_Y + 2; y++)
	//{
	//	for(uint x = 0; x < FLUID_GRID_SIZE_X + 2; x++)
	//	{
	//		XMVECTOR p = XMVectorSet(x, y, 0, 0);

	//		mFluidDensity[IDX(x,y)] = 0;

	//		densitySources[IDX(x,y)] = 0;

	//		mFluidVelX[IDX(x,y)] = 0;
	//		mFluidVelY[IDX(x,y)] = 0;

	//		mFluidVelXPrev[IDX(x,y)] = mFluidVelX[IDX(x,y)];
	//		mFluidVelYPrev[IDX(x,y)] = mFluidVelY[IDX(x,y)];

	//	}
	//}

	mFluidDensity[IDX((FLUID_GRID_SIZE_X + 2) / 2 + 1, 30)] = 0.01f * FLUID_GRID_SIZE_X * FLUID_GRID_SIZE_Y;
	mFluidDensity[IDX((FLUID_GRID_SIZE_X + 2) / 2 - 1, 30)] = 0.01f * FLUID_GRID_SIZE_X * FLUID_GRID_SIZE_Y;
	mFluidDensity[IDX((FLUID_GRID_SIZE_X + 2) / 2, 30)] = 0.01f * FLUID_GRID_SIZE_X * FLUID_GRID_SIZE_Y;
	mFluidDensity[IDX((FLUID_GRID_SIZE_X + 2) / 2, 30 + 1)] = 0.01f * FLUID_GRID_SIZE_X * FLUID_GRID_SIZE_Y;
	mFluidDensity[IDX((FLUID_GRID_SIZE_X + 2) / 2, 30 - 1)] = 0.01f * FLUID_GRID_SIZE_X * FLUID_GRID_SIZE_Y;
	//mFluidVelX[IDX((FLUID_GRID_SIZE_X + 2) / 2 + 1, 30)] = 100;
	//mFluidVelX[IDX((FLUID_GRID_SIZE_X + 2) / 2 - 1, 30)] = -100;
	mFluidVelY[IDX((FLUID_GRID_SIZE_X + 2) / 2, 30 + 1)] =  100;
	mFluidVelY[IDX((FLUID_GRID_SIZE_X + 2) / 2, 30 - 1)] =  -100;
}

void FluidView::init()
{
	srand(time(NULL));

	View::load();

	mgfx::Renderer * rdr = mgfx::Renderer::Instance;
	mFluidDensityTex = rdr->addTexture2D(NULL, FLUID_GRID_SIZE_X, FLUID_GRID_SIZE_Y, DXGI_FORMAT_R32_FLOAT, true);

	//D3D11_SHADER_RESOURCE_VIEW_DESC srDesc;
	//srDesc.Format = DXGI_FORMAT_R32_FLOAT;
	//srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
	//srDesc.Texture2D.MostDetailedMip = 0;
	//srDesc.Texture2D.MipLevels = 1;
	//device->CreateShaderResourceView( mFluidDensityTex, &srDesc, &mFluidDensitySRV );

	mFluidDensity = new float[FLUID_PROPERTY_ARRAY_SIZE];
	mFluidDensityPrev = new float[FLUID_PROPERTY_ARRAY_SIZE];

	mFluidVelX = new float[FLUID_PROPERTY_ARRAY_SIZE];
	mFluidVelY = new float[FLUID_PROPERTY_ARRAY_SIZE];

	mFluidVelXPrev = new float[FLUID_PROPERTY_ARRAY_SIZE];
	mFluidVelYPrev = new float[FLUID_PROPERTY_ARRAY_SIZE];

	XMVECTOR densityCenter = XMVectorSet((FLUID_GRID_SIZE_X + 2) / 2 - 0.5f, (FLUID_GRID_SIZE_Y + 2) / 2 - 0.5f, 0, 0);

	for(uint y = 0; y < FLUID_GRID_SIZE_Y + 2; y++)
	{
		for(uint x = 0; x < FLUID_GRID_SIZE_X + 2; x++)
		{
			XMVECTOR p = XMVectorSet(x, y, 0, 0);
			//float dist = XMVectorGetX( XMVector2Length( densityCenter - p ) );
			//if(dist == 0)
			//	mFluidDensity[IDX(x,y)] = 1;
			//else
			//	mFluidDensity[IDX(x,y)] = 1 / dist;

			mFluidDensity[IDX(x,y)] = 0;

			densitySources[IDX(x,y)] = 0;

			XMVECTOR dirVec = XMVector2Normalize(p - densityCenter) * 20;


			//mFluidVelX[IDX(x,y)] = -XMVectorGetY(dirVec);
			//mFluidVelY[IDX(x,y)] = XMVectorGetX(dirVec);

			mFluidVelX[IDX(x,y)] = 0;
			mFluidVelY[IDX(x,y)] = 0;

			//mFluidVelX[IDX(x,y)] = XMVectorGetX(dirVec);
			//mFluidVelY[IDX(x,y)] = XMVectorGetY(dirVec);

			//mFluidVelX[IDX(x,y)] = rand() / float(RAND_MAX) * 50;
			//mFluidVelY[IDX(x,y)] = rand() / float(RAND_MAX) * 50;

			mFluidVelXPrev[IDX(x,y)] = mFluidVelX[IDX(x,y)];
			mFluidVelYPrev[IDX(x,y)] = mFluidVelY[IDX(x,y)];

		}
	}

	mFluidDensity[IDX((FLUID_GRID_SIZE_X + 2) / 2, (FLUID_GRID_SIZE_Y + 2) / 2)] = 0.01f * FLUID_GRID_SIZE_X * FLUID_GRID_SIZE_Y;

	createSpriteBuffers();

	mShaderFluid = mgfx::loadShaderFromFile("SimpleTextured2D.fx");
	mShaderSprite = mgfx::loadShaderFromFile("Font.fx");

	mArrowTex = mgfx::loadTextureFromFile("arrow.bmp");

	mDiffuseStrength = 0.001f;
	mSourceStrength = 30.0f;

	mDrawVelocity = false;

	initGui();
}

void FluidView::unload()
{
	delete mFluidDensity;
	delete mFluidDensityPrev;
	delete mFluidVelX;
	delete mFluidVelY;
	delete mFluidVelXPrev;
	delete mFluidVelYPrev;

	View::unload();
}

void FluidView::update( float dt )
{
	// velocity

	addSources(mFluidVelX, velXSources, dt);
	addSources(mFluidVelY, velYSources, dt);
	//add_source ( N, u, u0, dt ); add_source ( N, v, v0, dt );
	//SWAP ( u0, u ); SWAP ( v0, v );

	//std::swap(mFluidVelX, mFluidVelXPrev);
	//std::swap(mFluidVelY, mFluidVelYPrev);

	//diffuse(1, mFluidVelX, mFluidVelXPrev, mDiffuseStrength, dt);
	//diffuse(2, mFluidVelY, mFluidVelYPrev, mDiffuseStrength, dt);
	
	project(mFluidVelX, mFluidVelY, pressure, divergence);

	std::swap(mFluidVelX, mFluidVelXPrev);
	std::swap(mFluidVelY, mFluidVelYPrev);
	
	advect(1, mFluidVelX, mFluidVelXPrev, mFluidVelXPrev, mFluidVelYPrev, dt);
	advect(2, mFluidVelY, mFluidVelYPrev, mFluidVelXPrev, mFluidVelYPrev, dt);

	project(mFluidVelX, mFluidVelY, pressure, divergence);

	// density
	addSources(mFluidDensity, densitySources, dt);

	memcpy(mFluidDensityPrev, mFluidDensity, sizeof(float) * FLUID_PROPERTY_ARRAY_SIZE);

	//if(sDiffuseDensity)
	//{
	//	std::swap(mFluidDensity, mFluidDensityPrev);
	//	diffuse(0, mFluidDensity, mFluidDensityPrev, mDiffuseStrength, dt);
	//}

	std::swap(mFluidDensity, mFluidDensityPrev);
	advect(0, mFluidDensity, mFluidDensityPrev, mFluidVelX, mFluidVelY, dt);
}

void FluidView::draw()
{
	updateTextures();

	mgfx::Renderer * rdr = mgfx::Renderer::Instance;

	rdr->setShader(mShaderFluid);
	rdr->setShaderResource("gTexture", mFluidDensityTex);
	rdr->drawFullScreenQuad();

	rdr->setShaderResource("gTexture", NULL);
	rdr->applyConstantsWithoutDrawing();

	if(mDrawVelocity)
		drawVelocity();

	mGui->draw();
}

bool FluidView::onWindowMessage( UINT msg, WPARAM wParam, LPARAM lParam )
{
	if(sendInputToGUI(msg, wParam, lParam))
		return true;

	static bool holdingLeft = false;
	static bool holdingRight = false;
	static int prevMouseX, prevMouseY;

	switch(msg)
	{
		case WM_LBUTTONDOWN:
			holdingLeft = true;
			prevMouseX = LOWORD(lParam);
			prevMouseY = HIWORD(lParam);
			break;

		case WM_LBUTTONUP:
			holdingLeft = false;
			break;

		case WM_RBUTTONDOWN:
			holdingRight = true;
			prevMouseX = LOWORD(lParam);
			prevMouseY = HIWORD(lParam);
		break;

		case WM_RBUTTONUP:
			holdingRight = false;
			break;

		case WM_MOUSEMOVE:
			{
				if(holdingLeft || holdingRight)
				{

					float xPrev = FLUID_GRID_SIZE_X * prevMouseX / (float)mcore::GlobalAppData::Instance.ScreenWidth;
					float yPrev = FLUID_GRID_SIZE_Y * prevMouseY / (float)mcore::GlobalAppData::Instance.ScreenHeight;
					float xCurr = FLUID_GRID_SIZE_X * LOWORD(lParam) / (float)mcore::GlobalAppData::Instance.ScreenWidth;
					float yCurr = FLUID_GRID_SIZE_Y * HIWORD(lParam) / (float)mcore::GlobalAppData::Instance.ScreenHeight;

					float xS = (std::min)(xPrev, xCurr); float xL = (std::max)(xPrev, xCurr);
					float yS = (std::min)(yPrev, yCurr); float yL = (std::max)(yPrev, yCurr);
					
					for(size_t y = yS; y <= yL; y++)
					{
						for(size_t x = xS; x <= xL; x++)
						{
							if(holdingLeft)
								densitySources[IDX((size_t)x + 1, (size_t)y + 1)] += mSourceStrength; // +1 to account for grid borders
							if(holdingRight)
							{
								velXSources[IDX((size_t)x + 1, (size_t)y + 1)] += 120*(LOWORD(lParam) - prevMouseX);
								velYSources[IDX((size_t)x + 1, (size_t)y + 1)] += 120*(HIWORD(lParam) - prevMouseY);
							}
						}
					}

					prevMouseX = LOWORD(lParam);
					prevMouseY = HIWORD(lParam);
				}
			}
			break;
	}
	return false;
}

void FluidView::initGui()
{
	mgui::Window * window = new mgui::Window(mgui::Rect(800, 50, 200, 500), "Fluids");
	mGui->addChild(*window);

	mgui::Label * label = new mgui::Label(mgui::Rect(10, 30, 100, 20), "Diff str");
	window->addChild(*label);

	mTextFieldDiffuseStrength = new mgui::TextField(mgui::Rect(120, 30, 60, 20), mgui::TextField::TYPE_FLOAT);
	mTextFieldDiffuseStrength->addListener(mgui::TextField::EVENT_TEXT_CHANGED, std::bind(&FluidView::textFieldDiffuseStrChanged, this, std::placeholders::_1));
	mTextFieldDiffuseStrength->setFloat(mDiffuseStrength);
	window->addChild(*mTextFieldDiffuseStrength);

	label = new mgui::Label(mgui::Rect(10, 60, 100, 20), "Source str");
	window->addChild(*label);

	mTextFieldSourceStrength = new mgui::TextField(mgui::Rect(120, 60, 60, 20), mgui::TextField::TYPE_FLOAT);
	mTextFieldSourceStrength->addListener(mgui::TextField::EVENT_TEXT_CHANGED, std::bind(&FluidView::textFieldSourceStrChanged, this, std::placeholders::_1));
	mTextFieldSourceStrength->setFloat(mSourceStrength);
	window->addChild(*mTextFieldSourceStrength);

	mgui::OnOffButton * onOffButton = new mgui::OnOffButton(mgui::Rect(10, 90, 160, 20), "Draw velocity");
	onOffButton->addListener(mgui::OnOffButton::EVENT_STATE_CHANGED, std::bind(&FluidView::buttonDrawVelSwitched, this, std::placeholders::_1));
	window->addChild(*onOffButton);

	onOffButton = new mgui::OnOffButton(mgui::Rect(10, 120, 160, 20), "Diffuse density");
	onOffButton->Enabled = sDiffuseDensity;
	onOffButton->addListener(mgui::OnOffButton::EVENT_STATE_CHANGED, std::bind(&FluidView::buttonSetDiffuseDensity, this, std::placeholders::_1));
	window->addChild(*onOffButton);


	label = new mgui::Label(mgui::Rect(10, 150, 100, 20), "Proj iter");
	window->addChild(*label);

	mTextFieldProjIter = new mgui::TextField(mgui::Rect(120, 150, 60, 20), mgui::TextField::TYPE_INT);
	mTextFieldProjIter->addListener(mgui::TextField::EVENT_TEXT_CHANGED, std::bind(&FluidView::buttonSetProjIter, this, std::placeholders::_1));
	mTextFieldProjIter->setInt(sProjNumIter);
	window->addChild(*mTextFieldProjIter);

	mgui::OnOffButton * pushButton = new mgui::OnOffButton(mgui::Rect(10, 180, 160, 20), "Clear");
	pushButton->addListener(mgui::OnOffButton::EVENT_STATE_CHANGED, std::bind(&FluidView::buttonReset, this, std::placeholders::_1));
	window->addChild(*pushButton);

	pushButton = new mgui::OnOffButton(mgui::Rect(10, 210, 160, 20), "Blow");
	pushButton->addListener(mgui::OnOffButton::EVENT_STATE_CHANGED, std::bind(&FluidView::buttonBlow, this, std::placeholders::_1));
	window->addChild(*pushButton);
}

void FluidView::updateTextures()
{
	uint rowPitch;
	byte * mem = mgfx::Renderer::Instance->mapTexture(mFluidDensityTex, &rowPitch, NULL);

	for( size_t row = 0; row < FLUID_GRID_SIZE_Y; row++ )
	{
		size_t rowStart = row * rowPitch;
		for( size_t col = 0; col < FLUID_GRID_SIZE_X; col++ )
		{
			*((float*)&mem[rowStart + col * 4]) = mFluidDensity[IDX(col + 1, row + 1)]; // +1 to account for borders in grid
		}
	}

	mgfx::Renderer::Instance->unmapTexture(mFluidDensityTex);
}

void FluidView::textFieldDiffuseStrChanged(const mgui::EventArgs & args)
{
	mDiffuseStrength = mTextFieldDiffuseStrength->getFloat();
}

void FluidView::textFieldSourceStrChanged(const mgui::EventArgs & args)
{
	mSourceStrength = mTextFieldSourceStrength->getFloat();
}

void FluidView::buttonDrawVelSwitched(const mgui::EventArgs & args)
{
	mDrawVelocity = !mDrawVelocity;
}

void FluidView::buttonSetDiffuseDensity(const mgui::EventArgs & args)
{
	sDiffuseDensity = !sDiffuseDensity;
}

void FluidView::buttonSetProjIter(const mgui::EventArgs & args)
{
	sProjNumIter = mTextFieldProjIter->getInt();
}

void FluidView::buttonReset(const mgui::EventArgs & args)
{
	reset();
}

void FluidView::buttonBlow(const mgui::EventArgs & args)
{
	blow();
}


void FluidView::createSpriteBuffers()
{
	// vertex buffer
	mgfx::VertexPositionTexture vertices[4];

	vertices[0].Position = XMFLOAT3(0.0f, -0.5f, 0.5f);
	vertices[1].Position = XMFLOAT3(0.0f,  0.5f, 0.5f);
	vertices[2].Position = XMFLOAT3(1.0f, -0.5f, 0.5f);
	vertices[3].Position = XMFLOAT3(1.0f,  0.5f, 0.5f);

	vertices[0].TextureCoord = XMFLOAT2(0, 0);
	vertices[1].TextureCoord = XMFLOAT2(0, 1);
	vertices[2].TextureCoord = XMFLOAT2(1, 0);
	vertices[3].TextureCoord = XMFLOAT2(1, 1);

	mSpriteVertexBuffer = mgfx::Renderer::Instance->addVertexBuffer(&vertices[0], 4, sizeof(mgfx::VertexPositionTexture));
	
	// index buffer
	short indices[6];

	indices[0] = 0;
	indices[1] = 1;
	indices[2] = 2;

	indices[3] = 1;
	indices[4] = 3;
	indices[5] = 2;

	mSpriteIndexBuffer = mgfx::Renderer::Instance->addIndexBuffer(indices, 6, sizeof(short));
}

void FluidView::drawVelocity()
{
	uint scrWid = mcore::GlobalAppData::Instance.ScreenWidth;
	uint scrHei = mcore::GlobalAppData::Instance.ScreenHeight;

	mgfx::Renderer * rdr = mgfx::Renderer::Instance;

	rdr->setVertexFormat(mgfx::VertexPositionTexture::VertexFormat);
	rdr->setVertexBuffer(mSpriteVertexBuffer);
	rdr->setIndexBuffer(mSpriteIndexBuffer);
	rdr->setPrimitiveType(mgfx::TRIANGLE_LIST);

	rdr->setShader(mShaderSprite);
	rdr->setShaderResource("gTexture", mArrowTex);

	for(size_t y = 0; y <= FLUID_GRID_SIZE_Y + 1; y+=4)
	{
		for(size_t x = 0; x <= FLUID_GRID_SIZE_X + 1; x+=4)
		{
			float u = mFluidVelX[IDX(x,y)];
			float v = mFluidVelY[IDX(x,y)];
			float angle = atan2(v, u);
			float length = sqrtf(u*u + v*v);



			XMMATRIX transform = XMMatrixMultiply(
				XMMatrixMultiply(
					XMMatrixScaling(length * 0.12f, length * 0.03f, 1.0f),
					XMMatrixRotationZ(-angle)),
				XMMatrixTranslation(x / float(FLUID_GRID_SIZE_X / 2) - 1.0f, -int(y) / float(FLUID_GRID_SIZE_Y / 2) + 1.0f, 0.0f)
			);

			rdr->setShaderMatrix("gWorld", (float*)&transform);
			
			rdr->drawIndexed();

		}
	}
}